#include "IniFile.h"
// #include "Logger.h"
#include <sstream>
#include <fstream>
#include <algorithm>
#include <cstring>
#include <iostream>

using namespace yazi::utility;

Value::Value() : m_value(""){

}

Value::Value(bool value){
    m_value = value ? "true" : "false";
}

Value::Value(int value){
    stringstream ss;
    ss << value;
    m_value = ss.str();
}

Value::Value(double value){
    stringstream ss;
    ss << value;
    m_value = ss.str();
}

Value::Value(const char *value){
    m_value = value;
}

Value::Value(const string &value){
    m_value = value;
}

Value &Value::operator=(bool value)
{
    m_value = value ? "true" : "false";
}

Value &Value::operator=(int value)
{
    stringstream ss;
    ss << value;
    m_value = ss.str();
}

Value &Value::operator=(double value)
{
    stringstream ss;
    ss << value;
    m_value = ss.str();
}
Value &Value::operator=(const char *value){
    m_value = value;
} 

Value &Value::operator=(const string &value){
    m_value = value;
}

Value::operator bool(){
    return m_value == "true" ? true : false;    
}

Value::operator int(){
    return atoi(m_value.c_str());
}

Value::operator double(){
    return atof(m_value.c_str());
}

Value::operator string(){
    return m_value;
}

Value::operator string() const {
    return m_value;
}


IniFile::IniFile(){

}

bool IniFile::load(const char* filename){
    ifstream fin(filename);
    if(fin.fail()){
        cerr << "IniFile load failed, filename: " << filename << endl;
        return false;
    }
    m_filename = filename;
    string line;
    string section;
    while(getline(fin, line)){
        line = trim(line);
        if(line[0] == '['){
            int pos = line.find(']');
            if(-1 != pos){
                section = trim(line.substr(1, pos - 1));
                m_sections[section];
            }
        }
        else if(line[0] == '#'){
            continue;
        }
        else{
            int pos = line.find('=');
            if(pos > 0){
                string key = trim(line.substr(0, pos));
                string value = trim(line.substr(pos + 1));
                auto it = m_sections.find(section);
                if(it == m_sections.end()){
                    cerr << "parsing error: section = " << section << ", key = " << key << endl;
                    return false;
                }
                m_sections[section][key] = value;
            }
        }
    }
    fin.close();
    return true;
}

bool IniFile::load(const string& filename){
    return load(filename.c_str());
}

string IniFile::trim(const string &str){
    string ret = str;
    int start = 0, end = str.size() - 1;
    while(start < str.size() && str[start] == ' ') ++start;
    while(end >= 0 && str[end] == ' ') --end;
    return str.substr(start, end - start + 1);
}

bool IniFile::has(const string &section){
    return m_sections.find(section) != m_sections.end();
}

bool IniFile::has(const string &section, const string &key){
    auto it = m_sections.find(section);
    if (it == m_sections.end())
        return false;
    return it->second.find(key) != it->second.end();
}

Value& IniFile::get(const string& section, const string& key){
    return m_sections[section][key];
}

void IniFile::set(const string& section, const string& key, const Value& value){
    m_sections[section][key] = value;
}

string IniFile::serial(){
    stringstream ss;
    for(auto it = m_sections.begin(); it != m_sections.end(); ++it){
        string sec_key = it->first;
        auto section = it->second;
        ss << "[" << sec_key << "]" << endl;
        for(auto iter = section.begin(); iter != section.end(); ++iter){
            ss << iter->first << " = " << (string)iter->second << endl;
        }
    }
    return ss.str();
}

void IniFile::show(){
    cout << serial();
}

void IniFile::save(const string& filename){
    ofstream fout(filename);
    if(fout.fail()){
        return;
    }
    fout << serial();
    fout.close();
}

void IniFile::remove(const string &section){
    auto it = m_sections.find(section);
    if(it == m_sections.end())
        return;
    m_sections.erase(section);
}

void IniFile::remove(const string &section, const string &key){
    auto it = m_sections.find(section);
    if(it == m_sections.end())
        return;
    auto iter = it->second.find(key);
    if(iter == it->second.end())
        return;
    it->second.erase(key);
}

void IniFile::clear(){
    m_sections.clear();
}

Section &IniFile::operator[](const string &section){
    return m_sections[section];
}
